package com.bsj.media.init.dto;

import com.bsj.consumerQ.function.HandleRun;
import com.bsj.consumerQ.method.QueueAndRun;
import com.bsj.media.init.NettyIntercomUntil;
import com.bsj.media.media.PcmEncoderAudio2;
import com.bsj.media.network.RTPAudioData;
import com.bsj.media.network.tcpNetty.NettySendUntil;
import com.bsj.media.tool.cmd.CmdReqString;
import com.bsj.tools.DataUntil;
import com.bsj.tools.HexStr;
import io.netty.channel.ChannelHandlerContext;
import lombok.extern.slf4j.Slf4j;

import java.util.List;

@Slf4j
public class AudioHandleInfo {

    QueueAndRun queueAndRun;

    private String terminalNo;

    private RTPAudioData rtpAudioInfo = new RTPAudioData();

    /**
     * 48000*32/8/25前端采样率,换算成字节最大数为
     */
    private int samplingSize = 7680;

    private byte[] lastBytes;

    /**
     * 客户端类型
     */
    private int clientType;

    private PcmEncoderAudio2 pcmEncoderAudio2;

    /**
     * 音频编码类型
     */
    private int audioType = 1;

    public String getTerminalNo(){
        return terminalNo;
    }


    private int initAudioEncoder() {
        pcmEncoderAudio2 = new PcmEncoderAudio2();
        int outChannels = 1;
        int outSampleRate = 8000;
        int outBitRate = 16000;
        int inChannels = 0;
        int inSampleRate = 0;
        int avSampleType = 0;
        if (clientType == CmdReqString.CLIENT_TYPE_PC) {
            // PC端
            inChannels = 1;
            inSampleRate = 48000;
            avSampleType = 3;
        } else if (clientType == CmdReqString.CLIENT_TYPE_APP) {
            inChannels = 1;
            inSampleRate = 8000;
            // AV_SAMPLE_FMT_S16
            avSampleType = 1;
        } else if (clientType == CmdReqString.CLIENT_TYPE_WECHAT) {
            // 小程序端
            inChannels = 1;
            inSampleRate = 48000;
            avSampleType = 3;
        } else {
            log.info("客户端类型不正确！");
            return 0;
        }
        if (!pcmEncoderAudio2.Init(audioType, outChannels, outSampleRate, outBitRate, inChannels, inSampleRate,
                avSampleType)) {
            log.warn(terminalNo + "初始化对讲音频编码失败！audioType:" + audioType);
            return 0;
        }
        if (audioType == 1) {
            // 对应1078协议音频负载 G711a
            rtpAudioInfo.setPt(6);
        } else if (audioType == 2) {
            // 对应1078协议音频负载 G726
            rtpAudioInfo.setPt(8);
        } else if (audioType == 0) {
            // 对应1078协议音频负载ADPCM_IMA
            rtpAudioInfo.setPt(26);
        }
        return 1;
    }

    public void push(byte[] bytes) {
        queueAndRun.push(bytes);
    }

    public void init(String terminalNoNow, int clientTypeNow) {
        this.terminalNo = terminalNoNow;
        this.clientType = clientTypeNow;
        initAudioEncoder();
        queueAndRun = new QueueAndRun(1, 10, 1);
        queueAndRun.start("AudioHandleInfo" + terminalNo, new HandleRun() {
            @Override
            public void doRun(List<byte[]> list) {
                for (byte[] bytes : list) {
                    //如果未空
                    byte[] send = null;
                    int length = bytes.length;
                    if (lastBytes == null) {
                        if (length == samplingSize) {
                            send = bytes;
                        } else if (length < samplingSize) {
                            lastBytes = bytes;
                            //要将剩余的一部分数据保存下来
                        } else {
                            lastBytes = new byte[length - samplingSize];
                            send = new byte[samplingSize];
                            //获得要发出去的数据
                            System.arraycopy(bytes, 0, send, 0, samplingSize);
                            //遗留下来的数据
                            System.arraycopy(bytes, samplingSize, lastBytes, 0, lastBytes.length);
                        }
                    } else {
                        int lastLen = lastBytes.length;
                        if ((lastLen + length) == samplingSize) {
                            //合并2个数组
                            send = DataUntil.concatAll(lastBytes, bytes);
                        } else if ((lastLen + length) > samplingSize) {
                            byte[] allBytes = DataUntil.concatAll(lastBytes, bytes);
                            send = new byte[samplingSize];
                            lastBytes = new byte[allBytes.length - samplingSize];
                            //获得要发出去的数据
                            System.arraycopy(allBytes, 0, send, 0, samplingSize);
                            //遗留下来的数据
                            System.arraycopy(allBytes, samplingSize, lastBytes, 0, lastBytes.length);
                        } else {
                            lastBytes = DataUntil.concatAll(lastBytes, bytes);
                        }
                    }
                    if (send != null) {
                        //log.info("terminalNo：{}", terminalNo);
                        // 设置SIM卡号
                        rtpAudioInfo.setSimId(HexStr.toArray(terminalNo));
                        handleCompleteData(send);
                    }
                }
            }
        });
    }

    /**
     * 处理出来的完整数据
     * @param bytes
     */
    private void handleCompleteData(byte[] bytes) {
        byte[] encoderBuffer = new byte[320];
        int encoderOffset = 0;
        int srcSampleNum = pcmEncoderAudio2.getSrcSampleNum();
        //转化数据,采样率变化
        int ret = pcmEncoderAudio2.Encodec(bytes, samplingSize, srcSampleNum, encoderBuffer, encoderOffset, srcSampleNum);
        //转化完成
        if (ret > encoderOffset) {
            //打成RTP数据
            byte[] send = rtpAudioInfo.packetAudioRTP(encoderBuffer, ret);
            ChannelHandlerContext gain = NettyIntercomUntil.gain(terminalNo);
            if (gain != null) {
                NettySendUntil.send(gain, send);
            }
        }
    }

    public void stop() {
        if (queueAndRun != null) {
            queueAndRun.stop();
        }
    }
}
